﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Colorful.Caching;
using Colorful.Furniture.MpManagement;
using Microsoft.Extensions.Options;
using SKIT.FlurlHttpClient.Wechat.Api;
using SKIT.FlurlHttpClient.Wechat.Api.Models;
using Volo.Abp;

namespace Colorful.Furniture.MiniProgram;

/// <summary>
///  微信公众平台号扩展(基于Skit的微信接口封装框架)
/// </summary>
public class WechatMiniProgramExtensions : IWechatMiniProgramExtensions
{
    private readonly IRedisCache _redisCache;
    private readonly WechatMiniProgramOptions _wechatOptions;

    public WechatMiniProgramExtensions(
        IOptions<WechatMiniProgramOptions> wechatMpOptions,
        IRedisCache redisCache)
    {
        _wechatOptions = wechatMpOptions.Value;
        _redisCache = redisCache;

        var wechatApiOptions = new WechatApiClientOptions
        {
            AppId = _wechatOptions.AppId,
            AppSecret = _wechatOptions.AppSecret
        };

        Client = new WechatApiClient(wechatApiOptions);
    }

    /// <summary>
    ///  获取令牌
    /// </summary>
    /// <returns></returns>
    public async Task<string> GetAccessTokenAsync()
    {
        return await GetAccessTokenAsync(_wechatOptions.AppId, _wechatOptions.AppSecret);
    }

    /// <summary>
    ///  客户端
    /// </summary>
    public WechatApiClient Client { get; set; }

    /// <summary>
    ///  获取令牌
    /// </summary>
    /// <param name="appId"></param>
    /// <param name="appSecret"></param>
    /// <returns></returns>
    public async Task<string> GetAccessTokenAsync(string appId, string appSecret)
    {
        if (string.IsNullOrWhiteSpace(appId))
            throw new ArgumentNullException(nameof(appId));

        if (string.IsNullOrWhiteSpace(appSecret))
            throw new ArgumentNullException(nameof(appSecret));

        var accessTokenKey = $"{CachePrefixConst.WechatMiniProgramAccessToken}:{_wechatOptions.AppId}";

        //从Redis中获取accessToken
        var accessTokenCache = await _redisCache.GetAsync<string>(accessTokenKey);

        if (!string.IsNullOrWhiteSpace(accessTokenCache)) return accessTokenCache;

        var result = await Client.ExecuteCgibinTokenAsync(new CgibinTokenRequest());

        HandleWxJsonResult(result);

        await _redisCache.SetAsync(accessTokenKey, result.AccessToken, result.ExpiresIn);

        return result.AccessToken;
    }

    /// <summary>
    ///  微信JSON结果
    /// </summary>
    /// <param name="wxJsonResultResponse"></param>
    public void HandleWxJsonResult<T>(T wxJsonResultResponse)
    {
        var wxJsonResult = wxJsonResultResponse as WechatApiResponse;

        if (wxJsonResult == null)
            throw new UserFriendlyException($"未能转换微信响应对象{nameof(wxJsonResultResponse)}");

        var returnCodeDictionary = new Dictionary<int, string>
        {
                {-1   ,  "系统繁忙，此时请开发者稍候再试"},
                {40001,  "获取 access_token 时 AppSecret 错误，或者 access_token 无效。请开发者认真比对 AppSecret 的正确性，或查看是否正在为恰当的公众号调用接口"},
                {40002,  "不合法的凭证类型"},
                {40003,  "不合法的 OpenID ，请开发者确认 OpenID （该用户）是否已关注公众号，或是否是其他公众号的 OpenID"},
                {40029,  "code 无效"},
                {45011,  "API 调用太频繁，请稍候再试"},
                {40226,  "高风险等级用户，小程序登录拦截 。风险等级详见用户安全解方案"},
                {40164,  "请在接口IP白名单中进行设置"},
                {40159,"path 不能为空，且长度不能大于1024"},
                {45029,"生成码个数总和到达最大个数限制"},
                {41030,"page路径不正确：根路径前不要填加 /，不能携带参数（参数请放在scene字段里），需要保证在现网版本小程序中存在，与app.json保持一致。\r\n设置check_path=false可不检查page参数。"},
                {40169,"scene 不合法"},
                {85096,"scancode_time为系统保留参数，不允许配置"},
                {40097,"参数错误"}
                //TODO 待补充
        };

        if (returnCodeDictionary.ContainsKey(wxJsonResult.ErrorCode))
            throw new UserFriendlyException($"[微信小程序]{returnCodeDictionary[wxJsonResult.ErrorCode]}", wxJsonResult.ErrorCode.ToString());

        if (wxJsonResult.ErrorCode != 0)
            throw new UserFriendlyException($"{wxJsonResult.ErrorMessage}", wxJsonResult.ErrorCode.ToString());
    }
}